#include <cstdio>
#include <cstdlib>
#include <string.h>
#include "vectclasses.hpp"
#include "inputclasses.hpp"

void Input::ReadGeneral(char * filename, VectorArray * inputvect, VectorArray * kernel, int * teacher)
{
    int N = 0;
	int K = 0;
	int M = 0;
    int flagVect = 0;
    int flagClass = 0;
    *teacher = -1;
    char *codeword = new char[255];
	FILE *fin;
	fin = fopen(filename,"rt");
	if (fin == 0)
	{
		printf("Couldn't open the input file!\n");
        return;
	}
    while (!feof(fin))
	{
	    fscanf(fin, "%s", codeword);
	    if (strcmp(codeword, "dimension") == 0)
        {
            fscanf(fin, "%d", &N);
        }
        else if (strcmp(codeword, "num_classes") == 0)
        {
            fscanf(fin, "%d", &K);
            K = 10;
        }
        else if (strcmp(codeword, "num_vectors") == 0)
        {
            fscanf(fin, "%d", &M);
        }
        else if (strcmp(codeword, "use_teacher") == 0)
        {
            fscanf(fin, "%d", teacher);
        }
	    else if (strcmp(codeword, "classes") == 0 && (flagClass == 0))
        {
            if ( (K == 0) || (N == 0) )
            {
                printf("You didn't supply the size or number of class vectors!\n");
                return;
            }
            kernel = new VectorArray(K, N);
			if (*teacher == 0)
			{
                kernel->read(fin);
			}
            flagClass = 1;
        }
	    else if ((strcmp(codeword, "vectors") == 0) && (flagVect == 0))
        {
            if ( (M == 0) || (N == 0) )
            {
                printf("You didn't supply the size or number of input vectors!\n");
                return;
            }
            inputvect = new VectorArray(M, N);
            inputvect->read(fin);
            flagVect = 1;
        }
    }
    fclose(fin);
	if ( (N == 0) || (K == 0) || (M == 0) || (*teacher == -1) || (flagVect == 0) || (flagClass == 0) )
	{
        printf("Your input file doesn't contain all the necessary information:\ndimension, num_classes, num_vectors, use_teacher, classes, vectors\n");
        return;
	}

	delete [] codeword;
}

inline void endian_swap(unsigned short& x)
{
    x = (x>>8) |
        (x<<8);
}

inline void endian_swap(unsigned int& x)
{
    x = (x>>24) |
        ((x<<8) & 0x00FF0000) |
        ((x>>8) & 0x0000FF00) |
        (x<<24);
}

void Input::ReadDigits(VectorArray * inputvect, VectorArray * kernel)
{
    FILE *fimages;
    int mydigits = 1000;
    unsigned int magicnum = 0;
    unsigned int digitnum;
    unsigned int rows;
    unsigned int cols;
    fimages = fopen("train-images.idx3-ubyte", "rb");
    if (fimages == NULL)
    {
        printf("Can't open images file.\n");
        return;
    }
    fread(&magicnum, 4, 1, fimages);
    endian_swap(magicnum);
    printf("magicnum %d\n", magicnum);
    fread(&digitnum, 4, 1, fimages);
    endian_swap(digitnum);
    printf("digitnum %d\n", digitnum);
    fread(&rows, 4, 1,fimages);
    endian_swap(rows);
    printf("rows %d\n", rows);
    fread(&cols, 4, 1,fimages);
    endian_swap(cols);
    printf("cols %d\n", cols);

    inputvect = new VectorArray(mydigits, rows*cols);
    kernel = new VectorArray(10, rows*cols);

    unsigned char tmp;
    for (int i = 0; i < mydigits; i++)
    {
        for (int j = 0; j < rows*cols; j++)
        {
            fread(&tmp, 1, 1, fimages);
            inputvect->at(i,j) = (double)tmp;
        }
    }
    fclose(fimages);
}

void Input::DigitClasses(VectorArray * kernel)
{
    int length = kernel->getVectLength();
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < length; j++)
        {
            kernel->at(i,j) = 0.0;
        }
    }
    unsigned int tmpread;
    unsigned int testdigits;
    FILE *ftestimages;
    FILE *ftestlabels;
    ftestlabels = fopen("t10k-labels.idx1-ubyte", "rb");
    if (ftestlabels == NULL)
    {
        printf("Can't open the test labels file.\n");
        return;
    }
    fread(&tmpread, 4, 1, ftestlabels);
    fread(&testdigits, 4, 1, ftestlabels);
    endian_swap(testdigits);
    char * testlabels = new char[testdigits];
    for (int i = 0; i < testdigits; i++)
    {
        fread(&(testlabels[i]), 1, 1, ftestlabels);
    }
    fclose(ftestlabels);
    ftestimages = fopen("t10k-images.idx3-ubyte", "rb");
    if (ftestimages == NULL)
    {
        printf("Can't open the test images file.\n");
        return;
    }
    fread(&tmpread, 4, 1, ftestimages);
    fread(&tmpread, 4, 1, ftestimages);
    fread(&tmpread, 4, 1, ftestimages);
    fread(&tmpread, 4, 1, ftestimages);
    unsigned char tmp;
    int truedigit;
    for (int i = 0; i < testdigits; i++)
    {
        truedigit = (int)(testlabels[i]);
        for (int j = 0; j < length; j++)
        {
            fread(&tmp, 1, 1, ftestimages);
            kernel->at(truedigit,j) += (double)tmp;
        }
    }
    fclose(ftestimages);
    for (int i = 0; i < 10; i++)
    {
        (kernel->getVector(i)).normalize();
    }
}
